package com.mugui.spring.net.baghandle;

import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.mugui.spring.base.Cache;
import com.mugui.spring.base.Filter;
import com.mugui.spring.base.Listener;
import com.mugui.spring.net.bean.Message;
import com.mugui.spring.net.bean.NetBag;
import com.mugui.spring.net.cache.CacheModel;
import com.mugui.spring.net.filter.FilterModel;
import com.mugui.spring.net.forward.ForwardNetBag;
import com.mugui.spring.net.listener.ListenerModel;
import com.mugui.spring.net.lock.NetBagHandle;
import com.mugui.spring.net.lock.SynchronizeLock;
import com.mugui.spring.net.sys.SysLogManager;
import com.mugui.spring.util.RedisAccess;

/**
 * 处理器管理
 * 
 * @author 木鬼
 *
 */
@Component
public class ProcessorManager {

	private HashMap<String, List<FilterModel>> filterMap = new HashMap<>();
	private HashMap<String, List<ListenerModel>> listenerMap = new HashMap<>();
	private HashMap<String, List<CacheModel>> cacheMap = new HashMap<>();

	@Autowired
	private SysLogManager dataManager;
	@Autowired
	private RedisAccess redisAccess;
	@Autowired
	private NetBagModuleManager manager;

	@Value("${spring.application.name:未命名}")
	private String appliction_name;

	private static long time = 0;

	void init() {
		dataManager.init(null);
		if (System.currentTimeMillis() - time > 30000) {
			synchronized (ProcessorManager.class) {
				if (System.currentTimeMillis() - time > 30000) {
					time = System.currentTimeMillis();
					if ("true".equals(redisAccess.get("listener_sys_info"))) {
						listener_sys_info = true;
					} else {
						listener_sys_info = false;
					}
					if ("true".equals(redisAccess.get("listener_sys_error"))) {
						listener_sys_error = true;
					} else {
						listener_sys_error = false;
					}
				}
			}
		}
	}

	static boolean listener_sys_info = false;
	static boolean listener_sys_error = false;

	/**
	 * 消息结果监听器
	 * 
	 * @auther 木鬼
	 * @param bag
	 * @param data
	 */
	void handleAddListener(NetBag bag, Message data) {
		List<ListenerModel> listenerModels = null;
		if ((listenerModels = listenerMap.get(bag.getFunc())) == null) {
			synchronized (listenerMap) {
				if ((listenerModels = listenerMap.get(bag.getFunc())) == null) {
					listenerMap.put(bag.getFunc(), listenerModels = new LinkedList<>());
					if (manager.getListenerMessage() != null) {
						Iterator<Entry<String, ListenerModel>> iterator = manager.getListenerMessage().entrySet()
								.iterator();
						while (iterator.hasNext()) {
							Entry<String, ListenerModel> entry = iterator.next();
							String string = bag.getFunc();
							boolean bool = handleListenerModel(string, entry.getValue());
							if (bool) {
								listenerModels.add(entry.getValue());
							}
						}
						listenerModels.sort(new Comparator<ListenerModel>() {
							@Override
							public int compare(ListenerModel o1, ListenerModel o2) {
								Listener filter1 = o1.getClass().getAnnotation(Listener.class);
								Listener filter2 = o2.getClass().getAnnotation(Listener.class);
								return filter1.weight() - filter2.weight();
							}
						});
					}
				}
			}
		}
		for (ListenerModel model : listenerModels) {
			try {
				if (listener_sys_info) {
					dataManager.ListenerLog().info(appliction_name, bag, data);
				}
				model.listener((Message) data, bag);
			} catch (Exception e) {
				e.printStackTrace();
				if (listener_sys_error) {
					dataManager.ListenerLog().error(appliction_name, bag, data, e);
				}
			}
		}
	}

	void saveCache(Message data, NetBag bag) {
		List<CacheModel> cacheModels = cacheLocal.get();
		for (CacheModel model : cacheModels) {
			try {
				if (listener_sys_info) {
					dataManager.CacheLog().info(appliction_name, bag, data);
				}
				model.save((Message) data, bag);
			} catch (Exception e) {
				e.printStackTrace();
				if (listener_sys_error) {
					dataManager.CacheLog().error(appliction_name, bag, data, e);
				}
			}
		}
		cacheLocal.remove();
	}

	private ThreadLocal<List<CacheModel>> cacheLocal = new ThreadLocal<>();

	/**
	 * 缓存区
	 * 
	 * @auther 木鬼
	 * @param bag
	 * @param cacheModels
	 * @return
	 */
	NetBag handleAddCache(NetBag bag) {
		List<CacheModel> cacheModels = null;
		if ((cacheModels = cacheMap.get(bag.getFunc())) == null) {
			synchronized (cacheMap) {
				if ((cacheModels = cacheMap.get(bag.getFunc())) == null) {
					cacheMap.put(bag.getFunc(), cacheModels = new LinkedList<>());
					if (manager.getCacheMessage() != null) {
						Iterator<Entry<String, CacheModel>> iterator = manager.getCacheMessage().entrySet().iterator();
						while (iterator.hasNext()) {
							Entry<String, CacheModel> entry = iterator.next();
							String string = bag.getFunc();
							boolean bool = handleCacheModel(string, entry.getValue());
							if (bool) {
								cacheModels.add(entry.getValue());
							}
						}
					}
				}
			}
		}
		cacheLocal.set(cacheModels);
		for (CacheModel model : cacheModels) {
			try {
				if (listener_sys_info) {
					dataManager.CacheLog().info(appliction_name, bag);
				}
				if (model.load(bag) == null) {
					if (listener_sys_info) {
						dataManager.CacheLog().info(appliction_name, bag);
					}
					return bag;
				}
			} catch (Exception e) {
				e.printStackTrace();
				if (listener_sys_error) {
					dataManager.CacheLog().error(appliction_name, bag, e);
				}
			}
		}
		if (listener_sys_info) {
			dataManager.CacheLog().info(appliction_name, bag, "");
		}
		return null;
	}

	/**
	 * 处理过滤器
	 * 
	 * @auther 木鬼
	 * @param bag
	 * @return
	 */
	NetBag handleAddFilter(NetBag bag) {
		List<FilterModel> filterModels = null;
		if ((filterModels = filterMap.get(bag.getFunc())) == null) {
			synchronized (filterMap) {
				if ((filterModels = filterMap.get(bag.getFunc())) == null) {
					filterMap.put(bag.getFunc(), filterModels = new LinkedList<>());
					if (manager.getFilterMessage() != null) {
						Iterator<Entry<String, FilterModel>> iterator = manager.getFilterMessage().entrySet()
								.iterator();
						while (iterator.hasNext()) {
							Entry<String, FilterModel> entry = iterator.next();
							String string = bag.getFunc();
							boolean bool = handleFilterModel(string, entry.getValue());
							if (bool) {
								filterModels.add(entry.getValue());
							}
						}
						filterModels.sort(new Comparator<FilterModel>() {
							@Override
							public int compare(FilterModel o1, FilterModel o2) {
								Filter filter1 = o1.getClass().getAnnotation(Filter.class);
								Filter filter2 = o2.getClass().getAnnotation(Filter.class);
								return filter2.weight() - filter1.weight();
							}
						});
					}
				}
			}

		}

		for (FilterModel model : filterModels) {
			try {
				if (listener_sys_info) {
					dataManager.FilterLog().info(appliction_name, bag);
				}
				if (model.filter(bag) == null) {
					netBagHandle.listener(null, bag);
					synchronizeLock.listener(null, bag);
					return bag;
				}
			} catch (Exception e) {
				e.printStackTrace();
				if (listener_sys_error) {
					dataManager.FilterLog().error(appliction_name, bag, e);
				}
			}

		}
		return null;
	}

	@Autowired
	private NetBagHandle netBagHandle;

	@Autowired
	private SynchronizeLock synchronizeLock;

	boolean handleFilterModel(String string, FilterModel filterModel) {
		Filter filter = filterModel.getClass().getAnnotation(Filter.class);
		String values[] = filter.value();
		boolean b = filter.type() == Filter.POSITIVE ? false : true;
		for (String value : values) {
			boolean bool = string.matches(value.replaceAll("[*]", MATCH_STR));
			switch (filter.type()) {
			case Filter.POSITIVE:
				if (bool) {
					return true;
				}
				break;
			case Filter.REVERSE:
				if (bool) {
					return false;
				}
				break;
			}
		}
		return b;
	}
	final static String MATCH_STR="[a-z A-Z 0-9 . _]*";

	boolean handleListenerModel(String string, ListenerModel listenerModel) {
		Listener listener = listenerModel.getClass().getAnnotation(Listener.class);
		String values[] = listener.value();
		boolean b = listener.type() == Listener.POSITIVE ? false : true;
		for (String value : values) {
			boolean bool = string.matches(value.replaceAll("[*]", MATCH_STR));
			switch (listener.type()) {
			case Listener.POSITIVE:
				if (bool) {
					return true;
				}
				break;
			case Listener.REVERSE:
				if (bool) {
					return false;
				}
				break;
			}
		}
		return b;
	}

	boolean handleCacheModel(String string, CacheModel cacheModel) {
		Cache listener = cacheModel.getClass().getAnnotation(Cache.class);
		String values[] = listener.value();
		boolean b = listener.type() == Cache.POSITIVE ? false : true;
		for (String value : values) {
			boolean bool = string.matches(value.replaceAll("[*]", MATCH_STR));
			switch (listener.type()) {
			case Cache.POSITIVE:
				if (bool) {
					return true;
				}
				break;
			case Cache.REVERSE:
				if (bool) {
					return false;
				}
				break;
			}
		}
		return b;
	}
	@Autowired
	ForwardNetBag forward;
	
	/**
	 * 分布式消息
	 * 
	 * @author 木鬼
	 * @param bag
	 * @return
	 */
	NetBag handleAddForward(NetBag bag) {

		String func[] = bag.getFunc().split("[.]");
		if (bag.getFunc().startsWith("&forward.insert.")) {
			Message message = null;
			try {
				if (listener_sys_info) {
					dataManager.ForwardLog().info(appliction_name, bag);
				}
				message = (Message) forward.invokeFunction(func[func.length - 1], bag);
				if (listener_sys_info) {
					dataManager.ForwardLog().info(appliction_name, bag, message);
				}
			} catch (Exception e) {
				e.printStackTrace();
				if (message != null) {
					message.setDate(e.getMessage());
				} else {
					message = Message.error("错误");
				}
				if (listener_sys_error) {
					dataManager.ForwardLog().error(appliction_name, bag, message, e);
				}
			}
			bag.setCode(200);
			bag.setData(message);
			return bag;
		}
		return null;
	}
}
